今天我們的目標是解決 樹狀搜尋問題
假設一個樹狀資料結構如下,該如何根據任意 id,找到這個 id 對應的文字內容呢 ?
const tree = {
    id:"a",
    text: "Today i don't feel like doing anything",
    children: [
        {
            id:"a1",
            text: "I just wanna lay in my bed",
            children: [
                 {
                    id:"a11",
                    text: "Don't feel like picking up my phone",
                    children: []
                },
            ]
        },
        {
            id:"a2",
            text: "So leave a message at the tone",
            children: []
        },
        {
            id:"a3",
            text: "Cus today I swear I'm not doing anything",
            children: []
        },
    ]
}
這個實在是跟結構化有點像,我們就默默變成五邊型吧
結構化程式設計和資料結構肯定息息相關
以這題來說可以選用 stack 做深度優先,也可以用 queue 做廣度優先
下面就先用 queue 做廣度優先,實作如下
function getNameById(target:string){
    
    let queue = [tree] // 初始化 queue
    while(queue.length > 0){
        let node = queue[0] // 處理最前面的點
        if(node.id === target){
            return node.text // 如果是目標點就結束並返回
        }
        for(let child of node.children){ // 不是目標點的話,把 children 塞進去
            queue.push(child)
        }
        queue.shift() // 第一個點處理完畢,處理下一個
    }
    return undefined
}
getNameById("all") //執行
再說一次 XD
物件導向就是把流程(方法)和資料(屬性)打包起來
class Tree {
    root: object
    constructor (root:object) {
        this.root = root
    }
    getNameById(target:string){
        let queue = [tree]
        while(queue.length > 0){
            let node = queue[0]
            if(node.id === target){
                return node.text
            }
            for(let child of node.children){
                queue.push(child)
            }
            queue.shift()
        }
        return undefined
    }
}
const myTree = new Tree(tree) // 實體化
myTree.getNameById("a11") // 執行
函數式非常注重型別,所以我們要先定義一個 Tree 介面
然後利用 js 自帶的 map / find 這些工具函式把組合一下
interface Tree {
    id: string,
    text: string,
    children: readonly Tree []
}
const getNameById = (target:string)=>(tree:Tree):string | undefined =>
    tree.id === target 
        ? tree.text // 找到,回傳 text
        : tree.children
            // - 往下層遞迴
            // - 省略 tree 的呼叫 .map(tree => getNameById(target)(tree))
            .map(getNameById(target)) 
            // - 從 list 中找不是 undefined 的 text
            // - 如果找不到,find function 也剛好會回傳 undefined
            .find(text=>text!==undefined) 
            
getNameById("a11")(tree) // 執行
明天會對以上範例進行更詳細的說明~